package es.unileon.rnag.jgen.operadores;

import java.util.ArrayList;
import java.util.List;

import es.unileon.rnag.jgen.Cromosoma;
import es.unileon.rnag.jgen.genes.Gen;

/**
 * Clase que implementa el Crossover uniforme
 * @author Abel Mayorga Gonz&aacute;lez
 * @author Sergio Fern&aacute;ndez Mart&iacute;nez
 * @version 1.0
 */
public class CrossoverUniforme extends Crossover {
	private float _probabilidad;
	
	/**
	 * Constructor
	 * @param p: Probabilidad de crossover en tanto por uno
	 * @param probabilidadEscogerPadre: Probabilidad de escoger los genes de uno de los padres
	 */
	public CrossoverUniforme(float p, float probabilidadEscogerPadre) {
		super(p);
		_probabilidad = probabilidadEscogerPadre;		
	}

	@Override
	public List<Cromosoma> operar(int generacion, List<Cromosoma> poblacion) {
		List<Cromosoma> hijos = new ArrayList<Cromosoma>();
		List<Cromosoma> listaCross = new ArrayList<Cromosoma>();
		List<Cromosoma> listaNoCross = new ArrayList<Cromosoma>();
		//Se escinde la poblacion en dos listas
		for(Cromosoma c: poblacion){
			if(Math.random()<_prob){
				listaCross.add(c);
			} else {
				listaNoCross.add(c);
			}
		}
		//Si el numero de individuos en la lista de crossover no es par
		//Se añade uno aleatoriamente de la otra lista
		if(listaCross.size()%2!=0){
			listaCross.add(listaNoCross.remove((int)Math.random()*listaNoCross.size()));
		}
		while(listaCross.size()>0){
			//Se cogen dos cromosomas
			Cromosoma c1 = listaCross.remove((int)(Math.random()*listaCross.size()));
			Cromosoma c2 = listaCross.remove((int)(Math.random()*listaCross.size()));
			//Se obtienen sus genes
			Gen[] g1 = c1.getGenes();
			Gen[] g2 = c2.getGenes();
			//Se intercambian dependiendo de la probabilidad de escoger el otro padre
			for(int i = 0; i < g1.length; i++){
				if (Math.random() < _probabilidad){
					Gen temp = g2[i];
					g2[i] = g1[i];
					g1[i] = temp;
				}
			}
			
			hijos.add(c1);
			hijos.add(c2);
		}
		hijos.addAll(listaNoCross);
		return hijos;
	}

}
